React Native Hermes 逆向实践

您所在的位置:网站首页 react native源码编译 React Native Hermes 逆向实践

React Native Hermes 逆向实践

2024-07-16 06:03| 来源: 网络整理| 查看: 265

0. 前言

Android 应用gl,使用了加固i,老版本的应用gl是js源码,新版本更新后,刚开始以为是加密了源码,分析后才知道是使用了Hermes优化引擎。

1. Hermes简介

Hermes是Facebook为React Native开源的一款javascript优化引擎。

 

原来的index.android.bundle是javascript的,被Hermes优化后变成了Bytecode。

 

Hermes优化的优化效果如下:

 

优化前:

 

优化后:

2. 前期准备2.1 绕过root检测

应用gl使用了加固i,在被root 的手机上运行,闪退。

 

绕过方法也很简单,在magisk的设置中,开启遵守排除列表,然后在配置排除列表中选择应用gl

 

应用被添加到排除列表后,将没办法使用lspoed,只能使用frida

2.2 绕过ssl pinning123456789101112131415161718192021222324252627function hook_ssl() {    Java.perform(function () {        var ClassName = "com.android.org.conscrypt.Platform";        var Platform = Java.use(ClassName);        var targetMethod = "checkServerTrusted";        var len = Platform[targetMethod].overloads.length;        console.log(targetMethod, len);        for (var i = 0; i < len; ++i) {            Platform[targetMethod].overloads[i].implementation = function () {                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);            };        }        var ClassName = "com.android.org.conscrypt.TrustManagerImpl";        var Platform = Java.use(ClassName);        var targetMethod = "checkTrustedRecursive";        var len = Platform[targetMethod].overloads.length;        console.log(targetMethod, len);        var ArrayList = Java.use("java.util.ArrayList")        var X509Certificate = Java.use("java.security.cert.X509Certificate");        for (var i = 0; i < len; ++i) {            Platform[targetMethod].overloads[i].implementation = function () {                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);                return ArrayList.$new();            };        }    });}2.3 抓包

 

抓包可以看到登录接口有个signcode加密参数,69e34d747c5757236142a19f4595d313 是32位字符串,猜测跟md5相关

3. signcode分析3.1 确定signcode的来源

由于我分析过应用gl前面版本,所以知道它是React Native开发的

 

但当你们拿到新app的时候,需要先对apk文件,app数据目录进行一次搜索

 

解压 apk, 使用命令 grep -r "signcode" *,搜索一下apk下有没有signcode,第一次没搜到(备注:应用gl把代码打包到assets/android-rn.zip里了)

 

在app的数据目录下,使用命令 grep -r "signcode" *,搜索一下,在文件./files/RN/rnbundle/index.android.bundle下搜索到了signcode

1Binary file ./files/RN/rnbundle/index.android.bundle matches

把./files/RN/rnbundle/index.android.bundle拿出来

1234cp ./files/RN/rnbundle/index.android.bundle /data/local/tmp/index.android.bundlechmod 777 /data/local/tmp/index.android.bundle adb pull /data/local/tmp/index.android.bundle

使用010editor打开后,就看到如下图的内容:

 

刚打开index.android.bundle, 我就猜测这个文件难道被加密了?(备注:在这之前我没有分析过被Hermes优化的应用)。

 

因为应用gl有加固i,我并没有研究加固,于是只能研究React Native的源码,看不能找到最终加载源码的地方

3.2 通过React Native源码研究的Hermes调用流程

下载源码 https://github.com/facebook/react-native.git

 

在源码中搜索 LoadScript,找到2个可疑的函数

123private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously); private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);

这2个函数是native,使用https://github.com/lasting-yang/frida_hook_libart/blob/master/hook_RegisterNatives.js,可以找到函数对应的so

12345678910111213[RegisterNatives] java_class: com.facebook.react.bridge.CatalystInstanceImpl name: jniLoadScriptFromAssets sig: (Landroid/content/res/AssetManager;Ljava/lang/String;Z)V fnPtr: 0xb4e99a85  fnOffset: 0x80a85  callee: 0xb4d2021d libhermes-executor-release.so!_ZN8facebook3jni6JClass15registerNativesESt16initializer_listI15JNINativeMethodE+0x20[RegisterNatives] java_class: com.facebook.react.bridge.CatalystInstanceImpl name: jniLoadScriptFromFile sig: (Ljava/lang/String;Ljava/lang/String;Z)V fnPtr: 0xb4e99aa1  fnOffset: 0x80aa1  callee: 0xb4d2021d libhermes-executor-release.so!_ZN8facebook3jni6JClass15registerNativesESt16initializer_listI15JNINativeMethodE+0x20 这时候会遇到一个问题,callee在libhermes-executor-release.so,使用ida打开libhermes-executor-release.so后,去fnOffset: 0x80a85和fnOffset: 0x80aa1找不到对应的函数。 于是使用frida的 Process.findModuleByAddress(ptr(0xb4e99a85)) 找jniLoadScriptFromAssets函数所在的模块,在libreactnativejni.so里面 {    "base": "0xb4e19000",    "name": "libreactnativejni.so",    "path": "/data/app/~~klydM6uPsWM_heluFCfyKQ==/com.xxxxx.xxx.xxxxxxxxxx.xxxxxx-zC5SUJ_WxA0rwldHieq_fg==/lib/arm/libreactnativejni.so",    "size": 815104}

对jniLoadScriptFromAssets和jniLoadScriptFromFile进行hook,需要配合hook_dlopen一起使用,因为frida注入的时候,libreactnativejni.so还没有加载。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748function hook_dlopen(module_name, fun) {    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");    if (android_dlopen_ext) {        Interceptor.attach(android_dlopen_ext, {            onEnter: function (args) {                var pathptr = args[0];                if (pathptr) {                    this.path = (pathptr).readCString();                    if (this.path.indexOf(module_name) >= 0) {                        this.canhook = true;                        console.log("android_dlopen_ext:", this.path);                    }                }            },            onLeave: function (retval) {                if (this.canhook) {                    fun();                }            }        });    }} function hook_libreactnativejni() {    let base_libreactnativejni = Module.findBaseAddress("libreactnativejni.so");    if (base_libreactnativejni == null) {        return;    }    let jniLoadScriptFromAssets = base_libreactnativejni.add(0x80a85);    let jniLoadScriptFromFile = base_libreactnativejni.add(0x80aa1);    //private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);    Interceptor.attach(jniLoadScriptFromAssets, {        onEnter(args) {            console.log("jniLoadScriptFromAssets:", Java.vm.tryGetEnv().getStringUtfChars(args[3]).readCString())        }    })    //private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);    Interceptor.attach(jniLoadScriptFromFile, {        onEnter(args) {            console.log("jniLoadScriptFromFile:", Java.vm.tryGetEnv().getStringUtfChars(args[2]).readCString(), Java.vm.tryGetEnv().getStringUtfChars(args[3]).readCString())        }    })} setImmediate(() => {    hook_dlopen("libreactnativejni.so", hook_libreactnativejni)    hook_libreactnativejni();})

jniLoadScriptFromFile被加载,传入参数为index.android.bundle文件路径

 

继续阅读源码,jniLoadScriptFromFile中会调用loadScriptFromString

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849void CatalystInstanceImpl::jniLoadScriptFromFile(    const std::string &fileName,    const std::string &sourceURL,    bool loadSynchronously) {  auto reactInstance = instance_;  if (!reactInstance) {    return;  }   switch (getScriptTagFromFile(fileName.c_str())) {    //根据文件头判断脚本类型,    case ScriptTag::MetroHBCBundle: {      std::unique_ptr script;      RecoverableError::runRethrowingAsRecoverable(          [&fileName, &script]() {            script = JSBigFileString::fromPath(fileName);          });      const char *buffer = script->c_str();      uint32_t bufferLength = (uint32_t)script->size();      uint32_t offset = 8;      while (offset < bufferLength) {        uint32_t segment = offset + 4;        uint32_t moduleLength =            bufferLength < segment ? 0 : *(((uint32_t *)buffer) + offset / 4);         reactInstance->loadScriptFromString(            std::make_unique(                std::string(buffer + segment, buffer + moduleLength + segment)),            sourceURL,            false);         offset += ((moduleLength + 3) & ~3) + 4;      }      break;    }    case ScriptTag::RAMBundle:      instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);      break;    case ScriptTag::String:    default: {      std::unique_ptr script;      RecoverableError::runRethrowingAsRecoverable(          [&fileName, &script]() {            script = JSBigFileString::fromPath(fileName);          });      instance_->loadScriptFromString(          std::move(script), sourceURL, loadSynchronously);    }  }}

loadScriptFromString

1234567891011void Instance::loadScriptFromString(    std::unique_ptr string,    std::string sourceURL,    bool loadSynchronously) {  SystraceSection s("Instance::loadScriptFromString", "sourceURL", sourceURL);  if (loadSynchronously) {    loadBundleSync(nullptr, std::move(string), std::move(sourceURL));  } else {    loadBundle(nullptr, std::move(string), std::move(sourceURL));  }}123456let loadScriptFromString = base_libreactnativejni.add(0xA0BF8 + 1);    Interceptor.attach(loadScriptFromString, {        onEnter(args) {            console.log("loadScriptFromString:", (args[1]), ptr(args[2]).add(Process.pointerSize * 2).readPointer().readCString(), args[3])        }    })

hook loadScriptFromString后,可以知道loadSynchronously为0, 继续分析loadBundle

123456789101112131415161718192021222324252627282930313233343536void Instance::loadBundle(    std::unique_ptr bundleRegistry,    std::unique_ptr string,    std::string sourceURL) {  callback_->incrementPendingJSCalls();  SystraceSection s("Instance::loadBundle", "sourceURL", sourceURL);  nativeToJsBridge_->loadBundle(      std::move(bundleRegistry), std::move(string), std::move(sourceURL));} //Instance::loadBundle调用了nativeToJsBridge_->loadBundle,void NativeToJsBridge::loadBundle(    std::unique_ptr bundleRegistry,    std::unique_ptr startupScript,    std::string startupScriptSourceURL) {  runOnExecutorQueue(      [this,       bundleRegistryWrap = folly::makeMoveWrapper(std::move(bundleRegistry)),       startupScript = folly::makeMoveWrapper(std::move(startupScript)),       startupScriptSourceURL =           std::move(startupScriptSourceURL)](JSExecutor *executor) mutable {        auto bundleRegistry = bundleRegistryWrap.move();        if (bundleRegistry) {          executor->setBundleRegistry(std::move(bundleRegistry));        }        try {          executor->loadBundle(              std::move(*startupScript), std::move(startupScriptSourceURL));        } catch (...) {          m_applicationScriptHasFailure = true;          throw;        }      });} //NativeToJsBridge::loadBundle里面调用了NativeToJsBridge::runOnExecutorQueue

runOnExecutorQueue的参数是一个Lambda表达式,它的回调函数里面调用了loadBundle,在源码中搜索loadBundle,找到了很多处实现代码,这时候我们酒不知道loadBundle具体实现在哪里,继续写hook代码hook_loadBundle

123456789101112131415161718function hook_loadBundle() {        //根据前面分析RN的一些so,可以发现大部分函数符号都还在so里面,那么我们通过DebugSymbol的findFunctionsMatching,找到所有loadBundle函数,并进行hook    DebugSymbol.findFunctionsMatching("*loadBundle*").map(addr => {        Interceptor.attach(addr, {            onEnter(args) {                console.log("loadBundle:", DebugSymbol.fromAddress(addr));            }        })    })}hook 结果如下: loadBundle: 0xbb70699d libreactnativejni.so!_ZN8facebook5react8Instance10loadBundleENSt6__ndk110unique_ptrINS0_17RAMBundleRegistryENS2_14default_deleteIS4_EEEENS3_IKNS0_11JSBigStringENS5_IS9_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEloadBundle: 0xbb70a845 libreactnativejni.so!_ZN8facebook5react16NativeToJsBridge10loadBundleENSt6__ndk110unique_ptrINS0_17RAMBundleRegistryENS2_14default_deleteIS4_EEEENS3_IKNS0_11JSBigStringENS5_IS9_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEloadBundle: 0xbb9a5ec5 libhermes-executor-release.so!_ZN8facebook5react11JSIExecutor10loadBundleENSt6__ndk110unique_ptrIKNS0_11JSBigStringENS2_14default_deleteIS5_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE  最终找到了libhermes-executor-release.so的facebook::react::JSIExecutor::loadBundle函数

facebook::react::JSIExecutor::loadBundle函数中调用了evaluateJavaScript

12345678910111213141516171819void JSIExecutor::loadBundle(    std::unique_ptr script,    std::string sourceURL) {  SystraceSection s("JSIExecutor::loadBundle");   bool hasLogger(ReactMarker::logTaggedMarker);  std::string scriptName = simpleBasename(sourceURL);  if (hasLogger) {    ReactMarker::logTaggedMarker(        ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());  }  runtime_->evaluateJavaScript(      std::make_unique(std::move(script)), sourceURL);  flush();  if (hasLogger) {    ReactMarker::logTaggedMarker(        ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());  }}

hook "*evaluateJavaScript*",

12345678910111213141516171819202122232425function hook_evaluateJavaScript() {    DebugSymbol.findFunctionsMatching("*evaluateJavaScript*").map(addr => {                Interceptor.attach(addr, {            onEnter(args) {                console.log("evaluateJavaScript:", DebugSymbol.fromAddress(addr), "\r\n", print_native_stack("evaluateJavaScript", this));            }        })    })} 并没有找到evaluateJavaScript函数,只找到了一个evaluateJavaScriptWithSourceMap函数 evaluateJavaScript: 0xbb866775 libhermes.so!_ZN8facebook6hermes13HermesRuntime31evaluateJavaScriptWithSourceMapERKNSt6__ndk110shared_ptrIKNS_3jsi6BufferEEES9_RKNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE  [evaluateJavaScript] called from:0xbb867431 libhermes.so!0x114310xbb6605b9 libhermes-executor-common-release.so!0x1c5b90xbb727051 libhermes-executor-release.so!_ZN8facebook5react11JSIExecutor10loadBundleENSt6__ndk110unique_ptrIKNS0_11JSBigStringENS2_14default_deleteIS5_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE+0x18c0xbb4b94e7 libreactnativejni.so!0xa54e70xbb4ba133 libreactnativejni.so!_ZNKSt6__ndk18functionIFvPN8facebook5react10JSExecutorEEEclES4_+0x160xbb4a5ae1 libreactnativejni.so!0x91ae10xbb4961d3 libreactnativejni.so!_ZN8facebook3jni6detail13MethodWrapperIMNS_5react15JNativeRunnableEFvvEXadL_ZNS4_3runEvEES4_vJEE8dispatchENS0_9alias_refIPNS1_8JTypeForINS0_11HybridClassIS4_NS3_8RunnableEE8JavaPartESB_vE11_javaobjectEEE+0xe0xbb49617f libreactnativejni.so!_ZN8facebook3jni6detail15FunctionWrapperIPFvNS0_9alias_refIPNS1_8JTypeForINS0_11HybridClassINS_5react15JNativeRunnableENS6_8RunnableEE8JavaPartES8_vE11_javaobjectEEEESD_vJEE4callEP7_JNIEnvP8_jobjectSG_+0x260xee6708df libart.so!art_quick_generic_jni_trampoline+0x2e0x71915663 boot-framework.oat!0x54e663

evaluateJavaScriptWithSourceMap函数 在React Native源码中没有搜到,在另一个hermes项目(https://github.com/facebook/hermes)中找到了evaluateJavaScriptWithSourceMap函数和evaluateJavaScript函数

 

evaluateJavaScript函数对应so的地址0xbb867431 libhermes.so!0x11431

1234567891011121314jsi::Value HermesRuntimeImpl::evaluateJavaScript(    const std::shared_ptr &buffer,    const std::string &sourceURL) {  return evaluateJavaScriptWithSourceMap(buffer, nullptr, sourceURL);} jsi::Value HermesRuntime::evaluateJavaScriptWithSourceMap(    const std::shared_ptr &buffer,    const std::shared_ptr &sourceMapBuf,    const std::string &sourceURL) {  return impl(this)->evaluatePreparedJavaScript(      impl(this)->prepareJavaScriptWithSourceMap(          buffer, sourceMapBuf, sourceURL));}

evaluateJavaScriptWithSourceMap函数中调用了prepareJavaScriptWithSourceMap函数, 继续调用isHermesBytecode函数

12345678910HermesRuntimeImpl::prepareJavaScriptWithSourceMap(    const std::shared_ptr &jsiBuffer,    const std::shared_ptr &sourceMapBuf,    std::string sourceURL) {  std::pair bcErr{};  auto buffer = std::make_unique(std::move(jsiBuffer));  vm::RuntimeModuleFlags runtimeFlags{};  runtimeFlags.persistent = true;   bool isBytecode = isHermesBytecode(buffer->data(), buffer->size());

isHermesBytecode用来判断是否是Hermes的Bytecode

1234567891011121314bool HermesRuntime::isHermesBytecode(const uint8_t *data, size_t len) {  return hbc::BCProviderFromBuffer::isBytecodeStream(      llvh::ArrayRef(data, len));} static bool isBytecodeStream(llvh::ArrayRef aref) {    const auto *header =        reinterpret_cast(aref.data());    return (        aref.size() >= sizeof(hbc::BytecodeFileHeader) &&        header->magic == hbc::MAGIC);} const static uint64_t MAGIC = 0x1F1903C103BC1FC6;

MAGIC和index.android.bunddle的前8个字节是一直的,至此已经知道index.android.bundle并不是被应用gl加密了,而是被Hermes编译成了bytecode

123456789  BytecodeFileHeader(      uint64_t magic,        //0x1F1903C103BC1FC6      uint32_t version,    //0x54        表示是84版本,commit 0bac657c61ac47a3a9537d982921f5f6c9630d41 (HEAD, tag: v0.8.1)      ......} hermes/include/hermes/BCGen/HBC/BytecodeVersion.h路径中有定义BYTECODE_VERSION const static uint32_t BYTECODE_VERSION = 84;3.3 反编译Hermes bytecode与回编译

前面的分析过程,已经知道了index.android.bundle是Hermes的bytecode,没办法直接查看源码,需要借助其他工具进行反编译

 

Hermes官方提供了hbcdump工具,可以进行反编译,但使用起来比较麻烦,有另一个开源工具hbctool可以对hermesbytecode进行反编译与回编译

 

https://github.com/bongtrop/hbctool 提供了59, 62, 74, 76版本的反编译

 

https://github.com/niosega/hbctool/tree/draft/hbc-v84 对84版本的Hermes进行补充

 

安装可以反编译84版本的hbctool

1pip install https://github.com/niosega/hbctool/archive/ac6fabb69a7229ed9764997d153d4f703d1381aa.zip

反编译

1hbctool disasm index.android.bundle bundle

回编译

1hbctool asm bundle index.android.bundle.re

bytecode反编译出来的代码如下:搜索两处能md5相关的代码

 

并不需要深入bytecode,指令详情,了解几个简单指令即可。

 

只需要写一个打印日志的函数,变成成bytecode,反编译后替换掉这两个函数就能看到这两个md5函数的输入参数

3.4 js代码编译成Hermes bytecode

先编译Hermes源码,会得到./build/bin/hermes工具,

 

test.js

12345678function hook_log(a, b) {    window.nativeLoggingHook(a + " " + b, 1);    return " ";} function test() {    hook_log("333", "555");}

写了一些简单的js代码,把test.js编译成bytecode

1./build/bin/hermes  -emit-binary -out test.hbc test.js

010editor打开test.hbc可以看到MAGIC

 

反编译test.hbc

1hbctool disasm test.hbc testdir

得到

12345678910111213141516171819Function1(3 params, 14 registers, 0 symbols):    GetGlobalObject         Reg8:0                                ; 先获取全局变量 Reg8:0    TryGetById              Reg8:4, Reg8:0, UInt8:1, UInt16:7    ; 通过window字符串从Reg8:0全局变量中拿到window变量,存放在Reg8:4    ; Oper[3]: String(7) 'window'     GetByIdShort            Reg8:3, Reg8:4, UInt8:2, UInt8:5    ; 从windows变量中拿nativeLoggingHook,存放在Reg8:3    ; Oper[3]: String(5) 'nativeLoggingHook'     LoadParam               Reg8:1, UInt8:1    LoadConstString         Reg8:0, UInt16:0    ; Oper[1]: String(0) ' '     Add                     Reg8:2, Reg8:1, Reg8:0    LoadParam               Reg8:1, UInt8:2    Add                     Reg8:2, Reg8:2, Reg8:1    LoadConstUInt8          Reg8:1, UInt8:1    Call3                   Reg8:1, Reg8:3, Reg8:4, Reg8:2, Reg8:1    ;调用window.nativeLoggingHook函数    Ret                     Reg8:0EndFunction3.5 替换bytecode,得到signcode算法

把反编译出来的bytecode,替换到md5函数中

 

需要对字符串的id进行修改,字符串对应hbctool反编译出来的string.json中的字符串id

123456789101112131415{    "id": 253,    "isUTF16": false,    "value": "window"},{    "id": 33087,    "isUTF16": false,    "value": "nativeLoggingHook"},{    "id": 18880,    "isUTF16": false,    "value": " "},12345678910111213141516171819Function13508(3 params, 14 registers, 0 symbols):    GetGlobalObject         Reg8:0    TryGetById              Reg8:4, Reg8:0, UInt8:1, UInt16:253    ; 修改字符串id UInt16:7-> UInt16:253    ; Oper[3]: String(254) 'window'     GetById                 Reg8:3, Reg8:4, UInt8:2, UInt16:33087    ;修改字符串id UInt8:5 -> UInt16:33087, 从UInt8改成UInt16, 需要把GetByIdShort修改成GetById指令    ; Oper[3]: String(4397) 'nativeLoggingHook'     LoadParam               Reg8:1, UInt8:1    LoadConstString         Reg8:0, UInt16:18880            ; 修改字符串id UInt16:0 -> UInt16:18880    ; Oper[1]: String(674) ' '     Add                     Reg8:2, Reg8:1, Reg8:0    LoadParam               Reg8:1, UInt8:2    Add                     Reg8:2, Reg8:2, Reg8:1    LoadConstUInt8          Reg8:1, UInt8:1    Call3                   Reg8:1, Reg8:3, Reg8:4, Reg8:2, Reg8:1    Ret                     Reg8:0EndFunction

再次回编译,得到index.android.bundle.re

1234hbctool asm bundle index.android.bundle.re md5sum index.android.bundle.re7eba6c20134268a82e5a0af948ca550b  index.android.bundle.re

现在替换app目录下的index.android.bundle

1234567adb push index.android.bundle.re /data/local/tmp/index.android.bundle.re adb shellsucd /data/data/com.pcakge.name/files/RN/rnbundle/cp index.android.bundle index.android.bundle.bak    # 对原来的文件备份cp /data/local/tmp/index.android.bundle.re index.android.bundle

结束app, 运行 adb logcat "*:S ReactNative:V ReactNativeJS:V", 再次运行app就可以到得到md5函数的输入参数

123ReactNativeJS: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAPPKEYGL_RN_D02F48E720CACLIENTANDROIDDEVICEIDBBC6AD7E-1561-4702-8C1E-3AAC682B4D8BENCRYPT1PASSWORD6666666666TIMESTAMPUINFO666666666VERSION3.1.0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX undefined XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX脱敏

算法分析完成

参考链接

https://github.com/facebook/react-native.git

 

https://github.com/lasting-yang/frida_hook_libart

 

https://github.com/facebook/hermes

 

https://github.com/bongtrop/hbctool

 

https://github.com/niosega/hbctool/tree/draft/hbc-v84

[培训]科锐软件逆向50期预科班报名即将截止,速来!!! 50期正式班报名火爆招生中!!!

最后于 2022-7-4 22:16 被Imyang编辑 ,原因: #逆向分析


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3